use crate::error::SysError;
use crate::file_system::read_general_json;
use crate::model::NpmModuleInfo;
use serde_json::Value;
use std::fs;
use std::path::Path;

pub fn merge_api_json(
    target_api_json_path: &Path,
    npm_module_info: &NpmModuleInfo,
) -> Result<(), Box<dyn std::error::Error>> {
    println!(
        r#"merge_api_json:
target_api_json_path:{:?}
module_api_json_path:{:?}
"#,
        target_api_json_path, npm_module_info.api_json
    );

    if npm_module_info.api_json.exists() {
        fs::write(
            target_api_json_path,
            merge_apis(
                &read_general_json(&npm_module_info.api_json)?,
                &read_general_json(target_api_json_path)?,
            )?
            .to_string(),
        )?;
    }
    println!("完成合并api.json文件:{:?}", target_api_json_path);
    Ok(())
}

fn merge_apis(source: &Value, target: &Value) -> Result<Value, Box<dyn std::error::Error>> {
    // 确保 source 和 target 都是对象，并且包含 "apis" 键
    if !source.is_object() || !target.is_object() {
        return Err(SysError::msg("Source or target is not a JSON object").into());
    }

    let source_map = source.as_object().unwrap();
    let target_map = target.as_object().unwrap();

    // 获取 "apis" 数组
    let bindings = Vec::<Value>::new();
    let source_apis = source_map
        .get("apis")
        .and_then(|v| v.as_array())
        .unwrap_or(&bindings);
    let target_apis = target_map
        .get("apis")
        .and_then(|v| v.as_array())
        .unwrap_or(&bindings);

    // 创建新的数组，将 target_apis 的内容和 source_apis 的内容合并
    let mut merged_apis: Vec<Value> = target_apis.to_vec();
    merged_apis.extend_from_slice(source_apis);

    // 创建新的 target 对象，并插入合并后的 "apis" 数组
    let mut new_target = target.clone();
    if let Some(target_object) = new_target.as_object_mut() {
        target_object.insert("apis".to_string(), Value::Array(merged_apis));
    } else {
        return Err(Box::from("Failed to modify target object"));
    }

    Ok(new_target)
}

#[cfg(test)]
mod tests {
    use super::*;
    use serde_json::json;

    #[test]
    fn test_merge_api_json_success() -> Result<(), Box<dyn std::error::Error>> {
        let source = json!({
            "apis": [
                { "name": "api1", "version": "v1" },
                { "name": "api2", "version": "v2" }
            ]
        });

        let target = json!({
            "apis": [
                { "name": "api0", "version": "v0" }
            ]
        });

        let expected = json!({
            "apis": [
                { "name": "api0", "version": "v0" },
                { "name": "api1", "version": "v1" },
                { "name": "api2", "version": "v2" }
            ]
        });

        let result = merge_apis(&source, &target)?;
        assert_eq!(result, expected);

        Ok(())
    }

    #[test]
    fn test_merge_api_json_target_no_apis() -> Result<(), Box<dyn std::error::Error>> {
        let source = json!({
            "apis": [
                { "name": "api1", "version": "v1" }
            ]
        });

        let target = json!({});

        let expected = json!({
            "apis": [
                { "name": "api1", "version": "v1" }
            ]
        });

        let result = merge_apis(&source, &target)?;
        assert_eq!(result, expected);

        Ok(())
    }

    #[test]
    fn test_merge_api_json_source_no_apis() -> Result<(), Box<dyn std::error::Error>> {
        let source = json!({});

        let target = json!({
            "apis": [
                { "name": "api0", "version": "v0" }
            ]
        });

        let expected = target.clone();

        let result = merge_apis(&source, &target)?;
        assert_eq!(result, expected);

        Ok(())
    }

    #[test]
    fn test_merge_api_json_invalid_input() {
        let source = json!("not an object");
        let target = json!({
            "apis": []
        });

        let result = merge_apis(&source, &target);

        assert!(result.is_err());
    }
}
